package com.rc.saas.tenant.interceptor;

import com.rc.saas.tenant.base.BaseModel;
import com.rc.saas.tenant.common.constant.ShiroConstants;
import com.rc.saas.tenant.common.enums.InterceptEnum;
import com.rc.saas.tenant.model.tenant.TenantUser;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;

import java.util.Date;
import java.util.Properties;

/**
 * MYBATIS更新拦截器
 * update方法（其实也就是SqlSession的新增，删除，修改操作），所有执行executor的update方法都会被该拦截器拦截到
 * Created by sven on 2019/1/11
 */
@Intercepts({
        @Signature(
                type = Executor.class,
                method = "update",
                args = {MappedStatement.class, Object.class})})
public class TenantUpdateInterceptor implements Interceptor {
    private static Logger logger = LogManager.getLogger(TenantUpdateInterceptor.class);

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 根据签名指定的args顺序获取具体的实现类
        // 1. 获取MappedStatement实例, 并获取当前SQL命令类型
        MappedStatement statement = (MappedStatement) invocation.getArgs()[0];
        SqlCommandType commandType = statement.getSqlCommandType();

        // 2. 获取当前正在被操作的类, 有可能是Java Bean, 也可能是普通的操作对象, 比如普通的参数传递
        // 普通参数, 即是 @Param 包装或者原始 Map 对象, 普通参数会被 Mybatis 包装成 Map 对象
        // 即是 org.apache.ibatis.binding.MapperMethod$ParamMap
        Object parameter = invocation.getArgs()[1];
        // 获取拦截器指定的方法类型, 通常需要拦截 update
        String methodName = invocation.getMethod().getName();

        String mapperId = statement.getId();
        logger.warn("更新拦截器, mapperid:{},methodName:{}, commandType:{}", mapperId, methodName, commandType);

//        //开放定时器任务
//        if (InterceptEnum.contains(statement.getId())) {
//            //继续执行
//            return invocation.proceed();
//        }

        // 3. 获取当前用户信息
        Session session = SecurityUtils.getSubject().getSession();
        TenantUser user = (TenantUser) session.getAttribute(ShiroConstants.SESSION_TENANT_USER_KEY);

        if (user != null) {
            if (parameter instanceof BaseModel) {
                // 4. 准备更新的实体类
                BaseModel entity = (BaseModel) parameter;
                //tenantMapper.selectColumnsByTable();

                //运营商ID(所有mapper需要增加tenantCode)，包括SqlSession的新增，删除，修改操作
                if (methodName.equals("update")) {
                    if (commandType.equals(SqlCommandType.INSERT)) { //INSERT
                        if (StringUtils.isBlank(entity.getTenantCode())) {
                            entity.setTenantCode(user.getTenantCode());
                        }

                        if (StringUtils.isBlank(entity.getCreatedBy())) {
                            entity.setCreatedBy(user.getLoginName());
                        }

                        if (entity.getCreatedTime() == null) {
                            entity.setCreatedTime(new Date());
                        }

                        logger.warn("INSERT拦截器, mapperid:{},methodName:{}, commandType:{}", mapperId, methodName, commandType);
                    } else if (commandType.equals(SqlCommandType.UPDATE)) {//UPDATE
                        logger.warn("UPDATE拦截器, 当前数据的运营商ID:{},登录户ID:{}", entity.getTenantCode(), user.getTenantCode());

                        //判断tenant_code是否一致,updateByPrimaryKeySelective 和updateByPrimaryKey 是根据ID更新数据，可能没有tenant_code
                        if (StringUtils.isNotBlank(entity.getTenantCode())) {
                            if (!user.getTenantCode().equals(entity.getTenantCode())) {
                                logger.error("更新失败,当前数据的运营商ID跟登录户ID不一致, 当前数据的运营商ID:{},登录户ID:{}", entity.getTenantCode(), user.getTenantCode());
                                throw new RuntimeException("更新失败,当前数据的运营商ID跟登录户ID不一致");
                            }
                        } else {
                            logger.warn("UPDATE拦截器找不到tenantCode, mapperid:{},methodName:{}, commandType:{},当前数据的运营商ID:{},登录户ID:{}",
                                    mapperId, methodName, commandType, entity.getTenantCode(), user.getTenantCode());
                        }

                        if (StringUtils.isBlank(entity.getLastUpdatedBy())) {
                            entity.setLastUpdatedBy(user.getLoginName());
                        }

                        if (entity.getLastUpdatedTime() == null) {
                            entity.setLastUpdatedTime(new Date());
                        }
                    } else if (commandType.equals(SqlCommandType.DELETE)) {//DELETE
                        logger.warn("DELETE拦截器, 当前数据的运营商ID:{},登录户ID:{}", entity.getTenantCode(), user.getTenantCode());

                        if (!user.getTenantCode().equals(entity.getTenantCode())) {
                            logger.error("删除失败,当前数据的运营商ID跟登录户ID不一致, 当前数据的运营商ID:{},登录户ID:{}", entity.getTenantCode(), user.getTenantCode());
                            throw new RuntimeException("删除失败,当前数据的运营商ID跟登录户ID不一致");
                        }
                    }
                }
            }
        } else {
            logger.warn("尚未登录...");
        }

        //继续执行
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object o) {
        return Plugin.wrap(o, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
